Amazon SQSのDead Letter Queueにメッセージが移動するタイミングを調べてみた
サーモン大好き、横山です。
今回はAmazon SQSの Dead Letter Queue
にメッセージが移動するタイミングを調べてみました。
Queueの作成
対象となる通常のQueueと Dead Letter Queue
を入れるQueueを作成します。
「新しいキューの作成」をクリックします。
先に Dead Letter Queue
を入れるQueueを作成していきます。
「キュー名」を demo_dlq
と入力し、他はデフォルト値で「キューの作成」をクリック。
パラメータ名 | 値 |
---|---|
キュー名 | demo_dlq |
Dead Letter Queue
を作成後は通常のQueueを以下のパラーメータに従って作成します。
書いていない部分はデフォルトで作成します。
パラメータ名 | 値 |
---|---|
キュー名 | demo |
再処理ポリシーの使用 | レ (チェックを入れる) |
デッドレターキュー | demo_dlq |
最大受信数 | 1 |
作成しましたら、それぞれのQueueURLをメモっておきます。
キュー名 | URL |
---|---|
demo | https://sqs.ap-northeast-1.amazonaws.com/123456789012/demo |
demo_dlq | https://sqs.ap-northeast-1.amazonaws.com/123456789012/demo_dlq |
次にQueueにデータをsend_message、receive_message、するプログラムをPythonで書いていきます。
前提
今回はMac上で試しますが、AWS CLIの aws configure
で、アクセスキー、シークレットキー、デフォルトリージョンが設定されているものとして作業を進めていきます。
環境構築
いつもの virtualenv
を作成し、パッケージを boto3
と click
というモジュールを入れます。
(参考: Welcome to the Click Documentation — Click Documentation (5.0))
$ virtualenv venv $ . venv/bin/activate (venv)$ pip install -U pip (venv)$ pip install boto3 click
ソースコード (run.py)
#!/usr/bin/env python # coding: utf8 # run.py import boto3 import click import pprint def init_sqs(): return boto3.client('sqs') @click.group() def _(): pass @_.command() @click.argument('queue_url') def send(queue_url): sqs = init_sqs() params = { 'QueueUrl': queue_url, 'MessageBody': 'send message', } resp = sqs.send_message(**params) pprint.pprint(resp, indent=4) @_.command() @click.argument('queue_url') def recv(queue_url): sqs = init_sqs() params = { 'QueueUrl': queue_url, 'AttributeNames': ['ApproximateReceiveCount'], } resp = sqs.receive_message(**params) pprint.pprint(resp, indent=4) if __name__ == '__main__': _()
単純に、sqs send_message
と sqs receive_message
をPythonで実行するコードです。
send_messageは、QueueUrl
と MessageBody
を、 receive_messageは、 QueueUrl
と ApproximateReceiveCount
を取得するために AttributeNames
を設定してAPIを投げるようにしています。
ちなみに、ApproximateReceiveCount
はQueueがメッセージを返した回数となっています。
(参考: ReceiveMessage - Amazon Simple Queue Service)
Queueにメッセージを投げる時は
(venv)$ python run.py send [queue_url]
Queueからメッセージを取得する時は
(venv)$ python run.py recv [queue_url]
と実行することで、取得出来ます。
検証
まずはじめに初期状態は以下の画像の様になっています。 demoキュー、demo_dlqキュー両方共空の状態です。
demoキューにsend_messageを投げる
(venv)$ python run.py send https://sqs.ap-northeast-1.amazonaws.com/123456789012/demo { u'MD5OfMessageBody': 'da29a3de5fd13de436de4f0dd4165206', u'MessageId': 'd31731b4-87dc-4298-bb18-a6e7c59f8603', 'ResponseMetadata': { 'HTTPStatusCode': 200, 'RequestId': 'beb23792-eaac-5c98-9ce7-78d634b23260'}}
demoキューにmessageを投げますと、demoキューが以下の様に1つメッセージを保持します。 確認するときに、画面の数字が変わらないとかありましたら、マネージドコンソールの右上の更新ボタンを押してください。
demoキューからreceive_messageを使い、Queueを取得する
(venv)$ python run.py recv https://sqs.ap-northeast-1.amazonaws.com/123456789012/demo { u'Messages': [ { u'Attributes': { 'ApproximateReceiveCount': '1'}, u'Body': 'send message', u'MD5OfBody': 'da29a3de5fd13de436de4f0dd4165206', u'MessageId': 'd31731b4-87dc-4298-bb18-a6e7c59f8603', u'ReceiptHandle': 'AQEB0kwuk19uzI/VKp0zwAd48sk8JR5hsa3p29XyogMJmGiuZpCudlLeDyu4lQlOZP5PGlxDkesmQNOCvWgF7qRFLCKSCtJQ+CVP/7IQCkhuv/LHVhgk1mJXec9B6NAsi7JderMFBAxkr9LrorGgCzRhduGNEdyznPXVHoZnuJwpHvhrr7IvCWefz8IDvyeDCiLl9BeHc6jyESMjxlG28SRNDJkY8TdCifU104h/26KzkfGZpkoaqOUMLZZnSQliWAEfdTcV6w+b2oDs9GTPuB2vxq1UXc5Qzh19RhKT51i1HS84ziP7N8sAyPsYRDnagKBwO84JX87u03sQg2bZDMWqjNSR+M1npc9Ln7Q737wNhTaaS24M78WaQCUiWpzYgHyM'}], 'ResponseMetadata': { 'HTTPStatusCode': 200, 'RequestId': '83ba4de2-8607-514f-82e8-02a658785ac1'}}
このようにメッセージを受け取る事が出来ます。
あるWorkerがQueueからメッセージを受け取ると、 可視性タイムアウト(Visible Timeout)
の設定時間だけ、同一メッセージをQueueから取得することができなくなります。
この機能を使って、一定時間内、他のWorkerに同じメッセージが渡らない様にします。
通常は処理を終えたら、WorkerがQueueにあるメッセージを削除し、別のメッセージを受け取り、作業します。
Dead Letter Queue
への移動タイミング
demoキューから取得したメッセージが削除されず、 可視性タイムアウト(Visible Timeout)
が発生すると、demoキューに戻ります。
そして、もう一度receive_messageでメッセージを取得しようとすると、利用可能なメッセージにメッセージがあるにもかかわらずメッセージを取得することが出来ませんでした。
python run.py recv https://sqs.ap-northeast-1.amazonaws.com/123456789012/demo { 'ResponseMetadata': { 'HTTPStatusCode': 200, 'RequestId': '7af78b35-8781-5ccf-9ce4-c4715853d01e'}}
マネージコンソールで、Queueを確認して見ると、 Dead Letter Queue
に設定したdemo_dlqにメッセージが移動しています。
この事により、キューを取得しようとした際に、 ApproximateReceiveCount
が 最大受信数(Maximum Receives)
の値以上だったら、そのままメッセージを返さず、 Dead Letter Queue
に設定したQueueに移動することがわかります。
Dead Letter Queue
に移動したメッセージの確認
python run.py recv https://sqs.ap-northeast-1.amazonaws.com/123456789012/demo_dlq { u'Messages': [ { u'Attributes': { 'ApproximateReceiveCount': '2'}, u'Body': 'send message', u'MD5OfBody': 'da29a3de5fd13de436de4f0dd4165206', u'MessageId': 'd31731b4-87dc-4298-bb18-a6e7c59f8603', u'ReceiptHandle': 'AQEBTECAZJ6pg2m1h1+fhRa0vUfc/8Ut2IRxuVxkUexSKnP95opRLk1STwcPbB04jh/KT3BNNu6MRqVJkZH1mMLqF7ef8RCDZuGcW//VEUAejcydm12q2u2lXz2m0CDuJE6SlPQjju6q419ewi4c5fp0o0EP8iEGI6wHwbhvdi1KhB7bQwnIfuEUw4FCyBfxbt0yB03HNSy1cLmkUssZucjhftutT/bcc/tucjOqzUZ3FxE+C25DWQ1kEzJdip4COrrYjfMdUXmvf7QKKnF6pc2V3eqc+2YkyoVB+kga0IxuZyg6yMhKqi7EIQRzU2M4kTd1z860TkG2j77e4vr5gDDbHBRP6V6g0GkIw0Dnonk4nzCzpdEvZ5k/XQD9xamtvj/JQBqU/bg3pH7h7DH40WegCg=='}], 'ResponseMetadata': { 'HTTPStatusCode': 200, 'RequestId': '178d7294-59f3-53b0-847d-3dd0b8de50de'}}
QueueUrlをdemo_dlqキュー側にしてreceive_messageをすると、先ほど取得したメッセージのMessageId
が一緒なので、同一メッセージだということがわかります。また、ApproximateReceiveCount
と ReceiptHandle
以外値が同じのメッセージということも確認できます。
まとめ
以上のことから以下の事がわかりました。
可視性タイムアウト(Visible Timeout)
では、元のキューに戻るだけでDead Letter Queue
にメッセージが移動することは無かった- receive_messageを行った時に、Queueの
Maximum Receives
と メッセージのApproximateReceiveCount
の値によって、そのQueueのメッセージとして取得出来るか、メッセージが取得出来ずにDead Letter Queue
にメッセージが移動するか決まる